package org.example.hutool;

import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Excel工具-ExcelUtil
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2022/12/16 10:37
 */
@RestController
public class ExcelUtilControl {

    /**
     * http://localhost:8080/excel/read1
     * ExcelReader getReader(InputStream bookStream)
     * ExcelReader getReader(InputStream bookStream, int sheetIndex)
     * ExcelReader getReader(InputStream bookStream, boolean closeAfterRead)
     * ExcelReader getReader(InputStream bookStream, String sheetName)
     * 1、从流中读取Excel为ExcelReader（比如从ClassPath中读取Excel文件）
     * <p>
     * reader = ExcelUtil.getReader(FileUtil.file("test.xlsx"), 0);
     * 1、通过sheet编号获取,索引从0开始，默认读取第一个，读取结束自动关闭流
     * List<List<Object>> read()
     * 1、读取工作簿中指定的Sheet的所有行列数据，一行使用 List<Object> 表示
     * 2、如果是多表头，对于合并了的单元格，会重新拆分赋值，比如第1行 2，3，4列合并了，值是 xx，则读取后第一个list 的2，3，4个元素值都是 xxx。
     * List<List<Object>> read(int startRowIndex, int endRowIndex)
     * List<List<Object>> read(int startRowIndex, int endRowIndex, boolean aliasFirstLine)
     * 读取工作簿中指定行中的内容
     * * @param startRowIndex 起始行（包含，从0开始计数）
     * * @param endRowIndex   结束行（包含，从0开始计数）
     * * @param aliasFirstLine 是否首行作为标题行转换别名
     */
    @GetMapping("/excel/read1")
    public List<List<Object>> read1() {
        String resourceName = "static/测试单位-001001_多表头.xlsx";
        InputStream asStream = ExcelUtilControl.class.getClassLoader().getResourceAsStream(resourceName);
        ExcelReader reader = ExcelUtil.getReader(asStream, 0);
        List<List<Object>> mapList = reader.read();
        // List<List<Object>> read = reader.read(1, Integer.MAX_VALUE);
        return mapList;
    }

    /**
     * http://localhost:8080/excel/read2
     * ExcelReader getReader(File bookFile)
     * ExcelReader getReader(File bookFile, int sheetIndex)
     * ExcelReader getReader(File bookFile, String sheetName)
     * 1、从文件中读取Excel为ExcelReader
     * * sheetIndex sheet序号，0表示第一个sheet
     * * sheetName sheet名，第一个默认是sheet1
     * List<Map<String, Object>> readAll()
     * 1、读取Excel为Map的列表，读取所有行，默认第一行做为标题，数据从第二行开始
     * 2、Map表示一行，标题为key，单元格内容为value
     * 3、只适合读取第一行是表头的文件，不适合读取多表头。
     * List<T> readAll(Class<T> beanType)
     * 1、读取Excel为Bean的列表，读取所有行，默认第一行做为标题，数据从第二行开始。
     * 2、第一个的表头名称必须POJO对象的属性名称对应上才能赋值。
     */
    @GetMapping("/excel/read2")
    public List<Map<String, Object>> read2() throws UnsupportedEncodingException {
        String resourceName = "static/测试单位-001005_事业人员.xlsx";
        URL resource = ExcelUtilControl.class.getClassLoader().getResource(resourceName);
        File file = new File(URLDecoder.decode(resource.getFile(), "utf-8"));

        ExcelReader reader = ExcelUtil.getReader(file);
        List<Map<String, Object>> readAll = reader.readAll();
        return readAll;
    }

    /**
     * http://localhost:8080/excel/read3
     * <p>
     * ExcelReader getReader(String bookFilePath)
     * ExcelReader getReader(String bookFilePath, int sheetIndex)
     * 1、获取Excel读取器，默认调用第一个sheet
     * * bookFilePath Excel文件路径，绝对路径或相对于ClassPath路径
     * * sheetIndex sheet序号，0表示第一个sheet
     * List<Object> readRow(int rowIndex)
     * 1、读取某一行数据，rowIndex 行号，从0开始。对于合并的单元格会自动拆分赋值。
     * Object readCellValue(int x, int y)
     * 1、读取某个单元格的值
     * * @param x X坐标，从0计数，即列号
     * * @param y Y坐标，从0计数，即行号
     * * @return 值，如果单元格无值返回null
     *
     * @return
     * @throws UnsupportedEncodingException
     */
    @GetMapping("/excel/read3")
    public List<Object> read3() {
        String resourceName = "static/测试单位-001001_多表头.xlsx";
        ExcelReader reader = ExcelUtil.getReader(resourceName);
        List<Object> readRow = reader.readRow(1);
        Object readCellValue = reader.readCellValue(1, 1);
        System.out.println(readCellValue);
        return readRow;
    }

    /**
     * List<Map<String, Object>> read(int headerRowIndex, int startRowIndex, int endRowIndex)
     * 1、读取Excel为Map的列表，Map表示一行，标题为key，单元格内容为value
     * * @param headerRowIndex 标题所在行，如果标题行在读取的内容行中间，这行做为数据将忽略
     * * @param startRowIndex  起始行（包含，从0开始计数）
     * * @param endRowIndex    读取结束行（包含，从0开始计数）
     * List<T> read(int headerRowIndex, int startRowIndex, Class<T> beanType)
     * * @param beanType       每行对应Bean的类型，即标题与对象的属性名称一致。
     *
     * @return
     */
    @GetMapping("/excel/read4")
    public List<Map<String, Object>> read4() {
        String resourceName = "static/测试单位-001001_多表头.xlsx";
        ExcelReader reader = ExcelUtil.getReader(resourceName);
        // 第4行作为标题行，第5行开始做正文内容行读取
        List<Map<String, Object>> read = reader.read(3, 4, Integer.MAX_VALUE);
        return read;
    }

    /**
     * List<List<Object>> read(int startRowIndex, int endRowIndex)
     * List<List<Object>> read(int startRowIndex, int endRowIndex, boolean aliasFirstLine)
     * 读取工作簿中指定行中的内容
     * * @param startRowIndex 起始行（包含，从0开始计数）
     * * @param endRowIndex   结束行（包含，从0开始计数）
     * * @param aliasFirstLine 是否首行作为标题行转换别名
     *
     * @return
     */
    @GetMapping("/excel/read5")
    public List<List<Object>> read5() {
        String resourceName = "static/测试单位-001001_多表头.xlsx";
        ExcelReader reader = ExcelUtil.getReader(resourceName);
        // 第4行作为标题行，第5行开始做正文内容行读取
        List<List<Object>> read = reader.read(1, Integer.MAX_VALUE);
        return read;
    }

    /**
     * readBySax：通过Sax方式读取Excel，同时支持03和07格式
     * 在标准的ExcelReader中，如果数据量较大，读取Excel会非常缓慢，并有可能造成内存溢出。因此针对大数据量的Excel，Hutool封装了Sax模式的读取方式。
     * 1、注意这种方式读取时，对于合并的单元格，不会自动拆分赋值，比如第1行 2，3，4列合并了，值是 xx，则读取后第一个list的第2个元素值是 xxx，而第3，4个元素是null。
     *
     * @return
     */
    @GetMapping("/excel/read6")
    public List<List<Object>> read6() {
        List<List<Object>> totalRowList = new ArrayList<>();
        String resourceName = "static/测试单位-001001_多表头.xlsx";
        ExcelUtil.readBySax(resourceName, 0, new ExcelRowHandler(totalRowList));
        return totalRowList;
    }

}
